package com.hao.product.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hao.common.code.ErrorCode;
import com.hao.common.execption.BusinessException;
import com.hao.product.app.feign.UserFeign;
import com.hao.product.app.model.dto.product.ProductAddRequest;
import com.hao.product.app.model.dto.product.ProductQueryRequest;
import com.hao.product.app.model.dto.product.ProductUpdateRequest;
import com.hao.product.app.model.entity.Product;
import com.hao.product.app.model.entity.ProductCategory;
import com.hao.product.app.model.vo.ProductVO;
import com.hao.product.app.service.ProductCategoryService;
import com.hao.product.app.service.ProductService;
import com.hao.product.app.mapper.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hao.product.app.constant.RedisConstant.REDIS_LOCK;

/**
* @author haoge
* @description 针对表【product(商品)】的数据库操作Service实现
* @createDate 2023-05-22 15:52:44
*/
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
    implements ProductService{

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private ProductCategoryService productCategoryService;


    @Override
    @Transactional
    public boolean addProduct(ProductAddRequest productAddRequest) {

        Product product = new Product();
        try {
            BeanUtils.copyProperties(product,productAddRequest);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        String categoryIds = productAddRequest.getCategoryIds();
        String[] split = categoryIds.split(",");
        List<Integer> categoryIdList = Arrays.stream(split).map(Integer::valueOf).collect(Collectors.toList());
        // TODO: 2023/5/22 可能需要校验类别表中 有没有对应的类别
        List<ProductCategory> productCategoryList = categoryIdList.stream().map(c -> {
            ProductCategory productCategory = new ProductCategory();
            productCategory.setCid(Long.valueOf(c));
            return productCategory;
        }).collect(Collectors.toList());
        // TODO: 2023/5/22 可以限制重试次数
        RLock lock = redissonClient.getLock(REDIS_LOCK + ":" + "add:product");
        try {
            while (true) {
                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
                    System.out.println("Lock:"+Thread.currentThread().getName());
                    boolean result = this.save(product);
                    if (!result) {
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "新增失败");
                    }
                    productCategoryList.forEach(productCategory -> productCategory.setPid(product.getId()));
                    boolean saveBatch = productCategoryService.saveBatch(productCategoryList);
                    if (!saveBatch) {
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "新增失败");
                    }
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("新增时出错"+e.getMessage());
            return false;
        }finally {
            if (lock.isHeldByCurrentThread()) {
                System.out.println("unLock:" + Thread.currentThread().getName());
                lock.unlock();
            }
        }
    }

    @Override
    public boolean updateProduct(ProductUpdateRequest productUpdateRequest) {
        Integer status = productUpdateRequest.getStatus();
        Integer stock = productUpdateRequest.getStock();

        if (status == 1 && stock <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "上架商品，库存不能没有");
        }
        Product product = new Product();

        try {
            BeanUtils.copyProperties(product,productUpdateRequest);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }

        RLock lock = redissonClient.getLock(REDIS_LOCK + ":" + "update:product");
        try {
            while (true) {
                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
                    boolean result = this.updateById(product);
                    if (!result) {
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                    }
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("更新时出错"+e.getMessage());
            return false;
        }finally {
            if (lock.isHeldByCurrentThread()) {
                System.out.println("unLock:" + Thread.currentThread().getName());
                lock.unlock();
            }
        }
    }

    @Override
    public Page<ProductVO> listByPage(ProductQueryRequest productQueryRequest) {

        QueryWrapper<Product> productQueryWrapper = new QueryWrapper<>();
        String name = productQueryRequest.getName();
        if (StringUtils.isNotBlank(name)) {
            productQueryWrapper.like("name", name);
        }
        String detail = productQueryRequest.getDetail();
        if (StringUtils.isNotBlank(detail)) {
            productQueryWrapper.like("detail", detail);
        }
        Double price = productQueryRequest.getPrice();
        if (price != null) {
            productQueryWrapper.eq("price", price);
        }
        String categoryIds = productQueryRequest.getCategoryIds();
        String[] cIds = categoryIds.split(",");
        List<Integer> collect = Arrays.stream(cIds).map(Integer::valueOf).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(collect)) {
            QueryWrapper<ProductCategory> productCategoryQueryWrapper = new QueryWrapper<>();
            productCategoryQueryWrapper.select("pid");
            productCategoryQueryWrapper.in("cid", collect);
            List<ProductCategory> productCategoryList = productCategoryService.list(productCategoryQueryWrapper);
            List<Long> pids = productCategoryList.stream().map(ProductCategory::getPid).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(pids)) {
                productQueryWrapper.in("id", pids);
            }
        }
        productQueryWrapper.eq("status", 1);
        Page<Product> productList = this.page(new Page<>(productQueryRequest.getPageNum(), productQueryRequest.getPageSize()), productQueryWrapper);
        Page<ProductVO> productVOPage = new PageDTO<>(productList.getCurrent(), productList.getSize(), productList.getTotal());
        List<ProductVO> productVOList = productList.getRecords().stream().map(p -> {
            ProductVO productVO = new ProductVO();
            try {
                BeanUtils.copyProperties(productVO, p);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }
            return productVO;
        }).collect(Collectors.toList());
        productVOPage.setRecords(productVOList);
        return productVOPage;
    }

    @Override
    public boolean decreaseProductStock(Long id, Integer count) {

        Product product = this.getById(id);
        if (product.getStock() < count) {
            return false;
        }
        product.setStock(product.getStock()-count);
        return this.updateById(product);
    }
}




